home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Magazine / UsingPDF / GhostScript / source / gs5.10 / gdevwpr2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-11-22  |  22.6 KB  |  805 lines

  1. /* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevwpr2.c */
  20. /*
  21.  * Microsoft Windows 3.n printer driver for Ghostscript.
  22.  * Original version by Russell Lang and
  23.  * L. Peter Deutsch, Aladdin Enterprises.
  24.  * Modified by rjl 1995-03-29 to use BMP printer code
  25.  */
  26.  
  27. /* This driver uses the printer default size and resolution and
  28.  * ignores page size and resolution set using -gWIDTHxHEIGHT and
  29.  * -rXxY.  You must still set the correct PageSize to get the
  30.  * correct clipping path.
  31.  * The code in win_pr2_getdc() does try to set the printer page
  32.  * size from the PostScript PageSize, but it isn't working
  33.  * reliably at the moment.
  34.  * 
  35.  * This driver doesn't work with some Windows printer drivers.
  36.  * The reason is unknown.  All printers to which I have access
  37.  * work. 
  38.  *
  39.  * rjl 1997-11-20
  40.  */
  41.  
  42. /* Supported printer parameters are
  43.  *  -dBitsPerPixel=n
  44.  *     Override what the Window printer driver returns.
  45.  *  -dNoCancel
  46.  *     Don't display cancel dialog box.  Useful for unattended or
  47.  *     console EXE operation.
  48.  */
  49.  
  50. #include "gdevprn.h"
  51. #include "gdevpccm.h"
  52.  
  53. #include "windows_.h"
  54. #include <shellapi.h>
  55. #include "gp_mswin.h"
  56.  
  57. #include "gp.h"
  58. #include "commdlg.h"
  59.  
  60.  
  61. /* Make sure we cast to the correct structure type. */
  62. typedef struct gx_device_win_pr2_s gx_device_win_pr2;
  63. #undef wdev
  64. #define wdev ((gx_device_win_pr2 *)dev)
  65.  
  66. /* Device procedures */
  67.  
  68. /* See gxdevice.h for the definitions of the procedures. */
  69. private dev_proc_open_device(win_pr2_open);
  70. private dev_proc_close_device(win_pr2_close);
  71. private dev_proc_print_page(win_pr2_print_page);
  72. private dev_proc_map_rgb_color(win_pr2_map_rgb_color);
  73. private dev_proc_map_color_rgb(win_pr2_map_color_rgb);
  74. private dev_proc_get_params(win_pr2_get_params);
  75. private dev_proc_put_params(win_pr2_put_params);
  76.  
  77. private void win_pr2_set_bpp(gx_device *dev, int depth);
  78.  
  79. private gx_device_procs win_pr2_procs =
  80.   prn_color_params_procs(win_pr2_open, gdev_prn_output_page, win_pr2_close,
  81.    win_pr2_map_rgb_color, win_pr2_map_color_rgb, 
  82.    win_pr2_get_params, win_pr2_put_params);
  83.  
  84.  
  85. /* The device descriptor */
  86. typedef struct gx_device_win_pr2_s gx_device_win_pr2;
  87. struct gx_device_win_pr2_s {
  88.     gx_device_common;
  89.     gx_prn_device_common;
  90.     HDC hdcprn;
  91.     bool nocancel;
  92.     DLGPROC lpfnAbortProc;
  93.     DLGPROC lpfnCancelProc;
  94. };
  95.  
  96. gx_device_win_pr2 far_data gs_mswinpr2_device = {
  97.   prn_device_std_body(gx_device_win_pr2, win_pr2_procs, "mswinpr2",
  98.   DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 72.0, 72.0,
  99.   0, 0, 0, 0,
  100.   0, win_pr2_print_page), /* depth = 0 */
  101.   0,    /* hdcprn */
  102.   0,    /* nocancel */
  103.   NULL,    /* lpfnAbortProc */
  104.   NULL    /* lpfnCancelProc */
  105. };
  106.  
  107. private int win_pr2_getdc(gx_device_win_pr2 *);
  108.  
  109. /* Open the win_pr2 driver */
  110. private int
  111. win_pr2_open(gx_device *dev)
  112. {    int code;
  113.     int depth;
  114.     PRINTDLG pd;
  115.     POINT offset;
  116.     POINT size;
  117.     float m[4];
  118.     FILE *pfile;
  119.  
  120.     if ((!wdev->nocancel) && (hDlgModeless)) {
  121.         /* device cannot opened twice since only one hDlgModeless */
  122.         fprintf(stderr, "Can't open mswinpr2 device twice\n");
  123.         return gs_error_limitcheck;
  124.     }
  125.  
  126.     /* get a HDC for the printer */
  127.         if (!win_pr2_getdc(wdev)) {
  128.         /* couldn't get a printer from -sOutputFile= */
  129.         /* Prompt with dialog box */
  130.         memset(&pd, 0, sizeof(pd));
  131.         pd.lStructSize = sizeof(pd);
  132.         pd.hwndOwner = hwndtext;
  133.         pd.Flags = PD_PRINTSETUP | PD_RETURNDC;
  134.         if (!PrintDlg(&pd)) {
  135.         /* device not opened - exit ghostscript */
  136.             return gs_error_Fatal;    /* exit Ghostscript cleanly */
  137.         }
  138.         GlobalFree(pd.hDevMode);
  139.         GlobalFree(pd.hDevNames);
  140.         pd.hDevMode = pd.hDevNames = NULL;
  141.         wdev->hdcprn = pd.hDC;
  142.     }
  143.     if (!(GetDeviceCaps(wdev->hdcprn, RASTERCAPS) != RC_DIBTODEV)) {
  144.         fprintf(stderr, "Windows printer does not have RC_DIBTODEV\n");
  145.         DeleteDC(wdev->hdcprn);
  146.         return gs_error_limitcheck;
  147.     }
  148.  
  149.     /* initialise printer, install abort proc */
  150. #ifdef __WIN32__
  151.     wdev->lpfnAbortProc = (DLGPROC)AbortProc;
  152. #else
  153. #ifdef __DLL__
  154.     wdev->lpfnAbortProc = (DLGPROC)GetProcAddress(phInstance, "AbortProc");
  155. #else
  156.     wdev->lpfnAbortProc = (DLGPROC)MakeProcInstance((FARPROC)AbortProc,phInstance);
  157. #endif
  158. #endif
  159.     Escape(wdev->hdcprn,SETABORTPROC,0,(LPSTR)wdev->lpfnAbortProc,NULL);  
  160.     if (Escape(wdev->hdcprn, STARTDOC, lstrlen(szAppName), szAppName, NULL) <= 0) {
  161.         fprintf(stderr, "Printer Escape STARTDOC failed\n");
  162. #if !defined(__WIN32__) && !defined(__DLL__)
  163.         FreeProcInstance((FARPROC)wdev->lpfnAbortProc);
  164. #endif
  165.         DeleteDC(wdev->hdcprn);
  166.         return gs_error_limitcheck;
  167.     }
  168.  
  169.     dev->x_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSX);
  170.     dev->y_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSY);
  171.     Escape(wdev->hdcprn, GETPHYSPAGESIZE, 0, NULL, (LPPOINT)&size);
  172.     gx_device_set_width_height(dev, (int)size.x, (int)size.y);
  173.     Escape(wdev->hdcprn, GETPRINTINGOFFSET, 0, NULL, (LPPOINT)&offset);
  174.     /* m[] gives margins in inches */
  175.     m[0] /*left*/ = offset.x / dev->x_pixels_per_inch;
  176.     m[3] /*top*/ = offset.y / dev->y_pixels_per_inch;
  177.     m[2] /*right*/ =
  178.         (size.x - offset.x - GetDeviceCaps(wdev->hdcprn, HORZRES))
  179.          / dev->x_pixels_per_inch;
  180.     m[1] /*bottom*/ =
  181.         (size.y - offset.y - GetDeviceCaps(wdev->hdcprn, VERTRES))
  182.          / dev->y_pixels_per_inch;
  183.     gx_device_set_margins(dev, m, true);
  184.  
  185.     depth = dev->color_info.depth;
  186.     if (depth == 0) {
  187.         /* Set parameters that were unknown before opening device */
  188.         /* Find out if the device supports color */
  189.         /* We recognize 1, 4 (but uses only 3), 8 and 24 bit color devices */
  190.         depth = GetDeviceCaps(wdev->hdcprn,PLANES) * GetDeviceCaps(wdev->hdcprn,BITSPIXEL);
  191.     }
  192.     win_pr2_set_bpp(dev, depth);
  193.  
  194.     /* gdev_prn_open opens a temporary file which we don't want */
  195.     /* so we specify the name now so we can delete it later */
  196.     pfile = gp_open_scratch_file(gp_scratch_file_name_prefix, 
  197.         wdev->fname, "wb");
  198.     fclose(pfile);
  199.     code = gdev_prn_open(dev);
  200.     /* delete unwanted temporary file */
  201.     unlink(wdev->fname);
  202.  
  203.     if (!wdev->nocancel) {
  204.         /* inform user of progress with dialog box and allow cancel */
  205. #ifdef __WIN32__
  206.     wdev->lpfnCancelProc = (DLGPROC)CancelDlgProc;
  207. #else
  208. #ifdef __DLL__
  209.     wdev->lpfnCancelProc = (DLGPROC)GetProcAddress(phInstance, "CancelDlgProc");
  210. #else
  211.     wdev->lpfnCancelProc = (DLGPROC)MakeProcInstance((FARPROC)CancelDlgProc, phInstance);
  212. #endif
  213. #endif
  214.         hDlgModeless = CreateDialog(phInstance, "CancelDlgBox", 
  215.         hwndtext, wdev->lpfnCancelProc);
  216.         ShowWindow(hDlgModeless, SW_HIDE);
  217.     }
  218.  
  219.     return code;
  220. };
  221.  
  222. /* Close the win_pr2 driver */
  223. private int
  224. win_pr2_close(gx_device *dev)
  225. {    int code;
  226.     int aborted = FALSE;
  227.     /* Free resources */
  228.  
  229.     if (!wdev->nocancel) {
  230.         if (!hDlgModeless)
  231.         aborted = TRUE;
  232.         else
  233.         DestroyWindow(hDlgModeless);
  234.         hDlgModeless = 0;
  235. #if !defined(__WIN32__) && !defined(__DLL__)
  236.         FreeProcInstance((FARPROC)wdev->lpfnCancelProc);
  237. #endif
  238.     }
  239.  
  240.     if (aborted)
  241.         Escape(wdev->hdcprn,ABORTDOC,0,NULL,NULL);
  242.     else
  243.         Escape(wdev->hdcprn,ENDDOC,0,NULL,NULL);
  244.  
  245. #if !defined(__WIN32__) && !defined(__DLL__)
  246.     FreeProcInstance((FARPROC)wdev->lpfnAbortProc);
  247. #endif
  248.     DeleteDC(wdev->hdcprn);
  249.     code = gdev_prn_close(dev);
  250.     return code;
  251. }
  252.  
  253.  
  254. /* ------ Internal routines ------ */
  255.  
  256. #undef wdev
  257. #define wdev ((gx_device_win_pr2 *)pdev)
  258.  
  259. /************************************************/
  260.  
  261.  
  262. /* ------ Private definitions ------ */
  263.  
  264.  
  265. /* new win_pr2_print_page routine */
  266.  
  267. /* Write BMP header to memory, then send bitmap to printer */
  268. /* one scan line at a time */
  269. private int
  270. win_pr2_print_page(gx_device_printer *pdev, FILE *file)
  271. {    int raster = gdev_prn_raster(pdev);
  272.     /* BMP scan lines are padded to 32 bits. */
  273.     ulong bmp_raster = raster + (-raster & 3);
  274.     ulong bmp_raster_multi;
  275.     int scan_lines, yslice, lines, i;
  276.     int width;
  277.     int depth = pdev->color_info.depth;
  278.     byte *row;
  279.     int y;
  280.     int code = 0;            /* return code */
  281.     MSG msg;
  282.     char dlgtext[32];
  283.     HGLOBAL hrow;
  284.  
  285.     struct bmi_s {
  286.         BITMAPINFOHEADER h;
  287.         RGBQUAD pal[256];
  288.     } bmi;
  289.  
  290.     scan_lines = dev_print_scan_lines(pdev);
  291.     width = pdev->width - ((dev_l_margin(pdev) + dev_r_margin(pdev) -
  292.         dev_x_offset(pdev)) * pdev->x_pixels_per_inch);
  293.  
  294.     yslice = 65535 / bmp_raster;    /* max lines in 64k */
  295.     bmp_raster_multi = bmp_raster * yslice;
  296.     hrow = GlobalAlloc(0, bmp_raster_multi);
  297.     row = GlobalLock(hrow);
  298.     if ( row == 0 )            /* can't allocate row buffer */
  299.         return_error(gs_error_VMerror);
  300.  
  301.     /* Write the info header. */
  302.  
  303.     bmi.h.biSize = sizeof(bmi.h);
  304.     bmi.h.biWidth = pdev->width;  /* wdev->mdev.width; */
  305.     bmi.h.biHeight = yslice;
  306.     bmi.h.biPlanes = 1;
  307.     bmi.h.biBitCount = pdev->color_info.depth;
  308.     bmi.h.biCompression = 0;
  309.     bmi.h.biSizeImage = 0;            /* default */
  310.     bmi.h.biXPelsPerMeter = 0;        /* default */
  311.     bmi.h.biYPelsPerMeter = 0;        /* default */
  312.  
  313.     /* Write the palette. */
  314.  
  315.     if ( depth <= 8 )
  316.     {    int i;
  317.         gx_color_value rgb[3];
  318.         LPRGBQUAD pq;
  319.         bmi.h.biClrUsed = 1 << depth;
  320.         bmi.h.biClrImportant = 1 << depth;
  321.         for ( i = 0; i != 1 << depth; i++ )
  322.         {    (*dev_proc(pdev, map_color_rgb))((gx_device *)pdev,
  323.                 (gx_color_index)i, rgb);
  324.             pq = &bmi.pal[i];
  325.             pq->rgbRed   = gx_color_value_to_byte(rgb[0]);
  326.             pq->rgbGreen = gx_color_value_to_byte(rgb[1]);
  327.             pq->rgbBlue  = gx_color_value_to_byte(rgb[2]);
  328.             pq->rgbReserved = 0;
  329.         }
  330.     }
  331.     else {
  332.         bmi.h.biClrUsed = 0;
  333.         bmi.h.biClrImportant = 0;
  334.     }
  335.  
  336.     if (!wdev->nocancel) {
  337.         sprintf(dlgtext, "Printing page %d", (int)(pdev->PageCount)+1);
  338.         SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PRINTING), dlgtext);
  339.         ShowWindow(hDlgModeless, SW_SHOW);
  340.     }
  341.  
  342.     for ( y = 0; y < scan_lines; ) {
  343.         /* copy slice to row buffer */
  344.         if (y > scan_lines - yslice)
  345.         lines = scan_lines - y;
  346.         else
  347.         lines = yslice;
  348.         for (i=0; i<lines; i++)
  349.             gdev_prn_copy_scan_lines(pdev, y+i, 
  350.             row + (bmp_raster*(lines-1-i)), raster);
  351.         SetDIBitsToDevice(wdev->hdcprn, 0, y, pdev->width, lines,
  352.         0, 0, 0, lines,
  353.         row,
  354.         (BITMAPINFO FAR *)&bmi, DIB_RGB_COLORS);
  355.         y += lines;
  356.  
  357.         if (!wdev->nocancel) {
  358.         /* inform user of progress */
  359.         sprintf(dlgtext, "%d%% done", (int)(y * 100L / scan_lines));
  360.         SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PCDONE), dlgtext);
  361.         }
  362.  
  363.         /* process message loop */
  364.         while (PeekMessage(&msg, hDlgModeless, 0, 0, PM_REMOVE)) {
  365.         if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg))
  366.         {
  367.             TranslateMessage(&msg);
  368.             DispatchMessage(&msg);
  369.         }
  370.         }
  371.         if ((!wdev->nocancel) && (hDlgModeless == 0)) {
  372.             /* user pressed cancel button */
  373.         break;
  374.         }
  375.     }
  376.  
  377.     if ((!wdev->nocancel) && (hDlgModeless == 0))
  378.         code = gs_error_Fatal;    /* exit Ghostscript cleanly */
  379.     else {
  380.         /* push out the page */
  381.         if (!wdev->nocancel)
  382.         SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PCDONE), 
  383.             "Ejecting page...");
  384.         Escape(wdev->hdcprn,NEWFRAME,0,NULL,NULL);
  385.         if (!wdev->nocancel)
  386.         ShowWindow(hDlgModeless, SW_HIDE);
  387.     }
  388.  
  389. bmp_done:
  390.     GlobalUnlock(hrow);
  391.     GlobalFree(hrow);
  392.  
  393.     return code;
  394. }
  395.  
  396. /* combined color mappers */
  397.  
  398. /* 24-bit color mappers (taken from gdevmem2.c). */
  399. /* Note that Windows expects RGB values in the order B,G,R. */
  400.  
  401. /* Map a r-g-b color to a color index. */
  402. private gx_color_index
  403. win_pr2_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
  404.   gx_color_value b)
  405. {
  406.     switch(dev->color_info.depth) {
  407.       case 1:
  408.     return gdev_prn_map_rgb_color(dev, r, g, b);
  409.       case 4:
  410.     /* use only 8 colors */
  411.     return  (r > (gx_max_color_value / 2 + 1) ? 4 : 0) +
  412.              (g > (gx_max_color_value / 2 + 1) ? 2 : 0) +
  413.              (b > (gx_max_color_value / 2 + 1) ? 1 : 0) ;
  414.       case 8:
  415.     return pc_8bit_map_rgb_color(dev, r, g, b);
  416.       case 24:
  417.     return gx_color_value_to_byte(r) +
  418.            ((uint)gx_color_value_to_byte(g) << 8) +
  419.            ((ulong)gx_color_value_to_byte(b) << 16);
  420.     }
  421.     return 0; /* error */
  422. }
  423.  
  424. /* Map a color index to a r-g-b color. */
  425. private int
  426. win_pr2_map_color_rgb(gx_device *dev, gx_color_index color,
  427.   gx_color_value prgb[3])
  428. {
  429.     switch(dev->color_info.depth) {
  430.       case 1:
  431.     gdev_prn_map_color_rgb(dev, color, prgb);
  432.     break;
  433.       case 4:
  434.     /* use only 8 colors */
  435.     prgb[0] = (color & 4) ? gx_max_color_value : 0;
  436.     prgb[1] = (color & 2) ? gx_max_color_value : 0;
  437.     prgb[2] = (color & 1) ? gx_max_color_value : 0;
  438.     break;
  439.       case 8:
  440.     pc_8bit_map_color_rgb(dev, color, prgb);
  441.     break;
  442.       case 24:
  443.     prgb[2] = gx_color_value_from_byte(color >> 16);
  444.     prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
  445.     prgb[0] = gx_color_value_from_byte(color & 0xff);
  446.     break;
  447.     }
  448.     return 0;
  449. }
  450.  
  451. void
  452. win_pr2_set_bpp(gx_device *dev, int depth)
  453. {
  454.     if (depth > 8) {
  455.         static const gx_device_color_info win_pr2_24color = dci_std_color(24);
  456.         dev->color_info = win_pr2_24color;
  457.     }
  458.     else if ( depth >= 8 ) {
  459.         /* 8-bit (SuperVGA-style) color. */
  460.         /* (Uses a fixed palette of 3,3,2 bits.) */
  461.         static const gx_device_color_info win_pr2_8color = dci_pc_8bit;
  462.         dev->color_info = win_pr2_8color;
  463.     }
  464.     else if ( depth >= 3) {
  465.         /* 3 plane printer */
  466.         /* suitable for impact dot matrix CMYK printers */
  467.         /* create 4-bit bitmap, but only use 8 colors */
  468.         static const gx_device_color_info win_pr2_4color = {3, 4, 1, 1, 2, 2};
  469.         dev->color_info = win_pr2_4color;
  470.     }
  471.     else {   /* default is black_and_white */
  472.         static const gx_device_color_info win_pr2_1color = dci_std_color(1);
  473.         dev->color_info = win_pr2_1color;
  474.     }
  475. }
  476.  
  477. /* Get device parameters */
  478. int
  479. win_pr2_get_params(gx_device *dev, gs_param_list *plist)
  480. {    int code = gdev_prn_get_params(dev, plist);
  481.     if (code >=0)
  482.        code = param_write_bool(plist, "NoCancel", 
  483.         &(((gx_device_win_pr2 *)dev)->nocancel));
  484.     return code;
  485. }
  486.  
  487. /* We implement this ourselves so that we can change BitsPerPixel */
  488. /* before the device is opened */
  489. int
  490. win_pr2_put_params(gx_device *dev, gs_param_list *plist)
  491. {    int ecode = 0, code;
  492.     int old_bpp = dev->color_info.depth;
  493.     int bpp = old_bpp;
  494.     bool nocancel = ((gx_device_win_pr2 *)dev)->nocancel;
  495.  
  496.     switch ( code = param_read_int(plist, "BitsPerPixel", &bpp) )
  497.     {
  498.     case 0:
  499.         if ( dev->is_open )
  500.           ecode = gs_error_rangecheck;
  501.         else
  502.           {    /* change dev->color_info is valid before device is opened */
  503.             win_pr2_set_bpp(dev, bpp);
  504.             break;
  505.           }
  506.         goto bppe;
  507.     default:
  508.         ecode = code;
  509. bppe:        param_signal_error(plist, "BitsPerPixel", ecode);
  510.     case 1:
  511.         break;
  512.     }
  513.  
  514.     switch ( code = param_read_bool(plist, "NoCancel", &nocancel) )
  515.     {
  516.     case 0:
  517.         if ( dev->is_open )
  518.           ecode = gs_error_rangecheck;
  519.         else
  520.           {
  521.             ((gx_device_win_pr2 *)dev)->nocancel = nocancel;
  522.             break;
  523.           }
  524.         goto nocancele;
  525.     default:
  526.         ecode = code;
  527. nocancele:    param_signal_error(plist, "NoCancel", ecode);
  528.     case 1:
  529.         break;
  530.     }
  531.  
  532.     if ( ecode >= 0 )
  533.         ecode = gdev_prn_put_params(dev, plist);
  534.     return ecode;
  535. }
  536.  
  537. #undef wdev
  538.  
  539. #ifndef __WIN32__
  540. #include <print.h>
  541. #endif
  542.  
  543.  
  544. /* Get Device Context for printer */
  545. private int
  546. win_pr2_getdc(gx_device_win_pr2 *wdev)
  547. {
  548. char *device;
  549. char *devices;
  550. char *p;
  551. char driverbuf[512];
  552. char *driver;
  553. char *output;
  554. char *devcap;
  555. int devcapsize;
  556. int size;
  557.  
  558. int i, n;
  559. POINT *pp;
  560. int paperindex;
  561. int paperwidth, paperheight;
  562. int orientation;
  563. int papersize;
  564. char papername[64];
  565. char drvname[32];
  566. HINSTANCE hlib;
  567. LPFNDEVMODE pfnExtDeviceMode;
  568. LPFNDEVCAPS pfnDeviceCapabilities;
  569. LPDEVMODE podevmode, pidevmode;
  570.  
  571. #ifdef __WIN32__
  572. HANDLE hprinter;
  573. #endif
  574.  
  575.  
  576.     /* first try to derive the printer name from -sOutputFile= */
  577.     /* is printer if name prefixed by \\spool\ */
  578.     if ( is_spool(wdev->fname) )
  579.     device = wdev->fname + 8;   /* skip over \\spool\ */
  580.     else
  581.     return FALSE;
  582.  
  583.     /* now try to match the printer name against the [Devices] section */
  584.     if ( (devices = gs_malloc(4096, 1, "win_pr2_getdc")) == (char *)NULL )
  585.     return FALSE;
  586.     GetProfileString("Devices", NULL, "", devices, 4096);
  587.     p = devices;
  588.     while (*p) {
  589.     if (strcmp(p, device) == 0)
  590.         break;
  591.     p += strlen(p) + 1;
  592.     }
  593.     if (*p == '\0')
  594.     p = NULL;
  595.     gs_free(devices, 4096, 1, "win_pr2_getdc");
  596.     if (p == NULL)
  597.     return FALSE;    /* doesn't match an available printer */
  598.  
  599.     /* the printer exists, get the remaining information from win.ini */
  600.     GetProfileString("Devices", device, "", driverbuf, sizeof(driverbuf));
  601.     driver = strtok(driverbuf, ",");
  602.     output = strtok(NULL, ",");
  603. #ifdef __WIN32__
  604.     if (is_win32s)
  605. #endif
  606.     {
  607.     strcpy(drvname, driver);
  608.     strcat(drvname, ".drv");
  609.     driver = drvname;
  610.     }
  611.  
  612.  
  613. #ifdef __WIN32__
  614.  
  615.     if (!is_win32s) {
  616.     if (!OpenPrinter(device, &hprinter, NULL))
  617.         return FALSE;
  618.     size = DocumentProperties(NULL, hprinter, device, NULL, NULL, 0);
  619.     if ( (podevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE)NULL ) {
  620.         ClosePrinter(hprinter);
  621.         return FALSE;
  622.     }
  623.     if ( (pidevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE)NULL ) {
  624.         gs_free(podevmode, size, 1, "win_pr2_getdc");
  625.         ClosePrinter(hprinter);
  626.         return FALSE;
  627.     }
  628.     DocumentProperties(NULL, hprinter, device, podevmode, NULL, DM_OUT_BUFFER);
  629.     pfnDeviceCapabilities = (LPFNDEVCAPS)DeviceCapabilities;
  630.     } else 
  631. #endif
  632.     {  /* Win16 and Win32s */
  633.     /* now load the printer driver */
  634.     hlib = LoadLibrary(driver);
  635.     if (hlib < (HINSTANCE)HINSTANCE_ERROR)
  636.         return FALSE;
  637.  
  638.     /* call ExtDeviceMode() to get default parameters */
  639.     pfnExtDeviceMode = (LPFNDEVMODE)GetProcAddress(hlib, "ExtDeviceMode");
  640.     if (pfnExtDeviceMode == (LPFNDEVMODE)NULL) {
  641.         FreeLibrary(hlib);
  642.         return FALSE;
  643.     }
  644.     pfnDeviceCapabilities = (LPFNDEVCAPS)GetProcAddress(hlib, "DeviceCapabilities");
  645.     if (pfnDeviceCapabilities == (LPFNDEVCAPS)NULL) {
  646.         FreeLibrary(hlib);
  647.         return FALSE;
  648.     }
  649.     size = pfnExtDeviceMode(NULL, hlib, NULL, device, output, NULL, NULL, 0);
  650.     if ( (podevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE)NULL ) {
  651.         FreeLibrary(hlib);
  652.         return FALSE;
  653.     }
  654.     if ( (pidevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE)NULL ) {
  655.         gs_free(podevmode, size, 1, "win_pr2_getdc");
  656.         FreeLibrary(hlib);
  657.         return FALSE;
  658.     }
  659.     pfnExtDeviceMode(NULL, hlib, podevmode, device, output,
  660.         NULL, NULL, DM_OUT_BUFFER);
  661.     }
  662.  
  663.     /* now find out what paper sizes are available */
  664.     devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERSIZE, NULL, NULL);
  665.     devcapsize *= sizeof(POINT);
  666.     if ( (devcap = gs_malloc(devcapsize, 1, "win_pr2_getdc")) == (LPBYTE)NULL )
  667.         return FALSE;
  668.     n = pfnDeviceCapabilities(device, output, DC_PAPERSIZE, devcap, NULL);
  669.     paperwidth = wdev->MediaSize[0] * 254 / 72; 
  670.     paperheight = wdev->MediaSize[1] * 254 / 72; 
  671.     papername[0] = '\0';
  672.     papersize = 0;
  673.     paperindex = -1;
  674.     orientation = DMORIENT_PORTRAIT;
  675.     pp = (POINT *)devcap;
  676.     for (i=0; i<n; i++, pp++) {
  677.     if ( (pp->x < paperwidth + 20) && (pp->x > paperwidth - 20) &&
  678.          (pp->y < paperheight + 20) && (pp->y > paperheight - 20) ) {
  679.         paperindex = i;
  680.         paperwidth = pp->x;
  681.         paperheight = pp->y;
  682.         break;
  683.     }
  684.     }
  685.     if (paperindex < 0) {
  686.     /* try again in landscape */
  687.         pp = (POINT *)devcap;
  688.     for (i=0; i<n; i++, pp++) {
  689.         if ( (pp->x < paperheight + 20) && (pp->x > paperheight - 20) &&
  690.          (pp->y < paperwidth + 20) && (pp->y > paperwidth - 20) ) {
  691.         paperindex = i;
  692.         paperwidth = pp->x;
  693.         paperheight = pp->y;
  694.         orientation = DMORIENT_LANDSCAPE;
  695.         break;
  696.         }
  697.     }
  698.     }
  699.     gs_free(devcap, devcapsize, 1, "win_pr2_getdc");
  700.  
  701.     /* get the dmPaperSize */
  702.     devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERS, NULL, NULL);
  703.     devcapsize *= sizeof(WORD);
  704.     if ( (devcap = gs_malloc(devcapsize, 1, "win_pr2_getdc")) == (LPBYTE)NULL )
  705.         return FALSE;
  706.     n = pfnDeviceCapabilities(device, output, DC_PAPERS, devcap, NULL);
  707.     if ( (paperindex >= 0) && (paperindex < n) )
  708.     papersize = ((WORD *)devcap)[paperindex];
  709.     gs_free(devcap, devcapsize, 1, "win_pr2_getdc");
  710.  
  711.     /* get the paper name */
  712.     devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERNAMES, NULL, NULL);
  713.     devcapsize *= 64;
  714.     if ( (devcap = gs_malloc(devcapsize, 1, "win_pr2_getdc")) == (LPBYTE)NULL )
  715.         return FALSE;
  716.     n = pfnDeviceCapabilities(device, output, DC_PAPERNAMES, devcap, NULL);
  717.     if ( (paperindex >= 0) && (paperindex < n) )
  718.     strcpy(papername, devcap + paperindex*64);
  719.     gs_free(devcap, devcapsize, 1, "win_pr2_getdc");
  720.     
  721.     memcpy(pidevmode, podevmode, size);
  722.  
  723.     pidevmode->dmFields = 0;
  724.  
  725.     pidevmode->dmFields |= DM_DEFAULTSOURCE;
  726.     pidevmode->dmDefaultSource = 0;
  727.  
  728.     pidevmode->dmFields |= DM_ORIENTATION;
  729.     pidevmode->dmOrientation = orientation;
  730.  
  731.     if (papersize)
  732.         pidevmode->dmFields |=  DM_PAPERSIZE;
  733.     else
  734.         pidevmode->dmFields &= (~DM_PAPERSIZE);
  735.     pidevmode->dmPaperSize = papersize;
  736.  
  737.     pidevmode->dmFields |=  (DM_PAPERLENGTH | DM_PAPERWIDTH);
  738.     pidevmode->dmPaperLength = paperheight;
  739.     pidevmode->dmPaperWidth = paperwidth;
  740.  
  741.  
  742. #ifdef WIN32
  743.     if (!is_win32s) {
  744.     /* change the page size by changing the form */
  745.     /* WinNT only */
  746.     /*  at present, changing the page size isn't working under Win NT */
  747.     /* Win95 returns FALSE to GetForm */
  748.     LPBYTE lpbForm;
  749.     FORM_INFO_1 *fi1;
  750.     DWORD dwBuf;
  751.     DWORD dwNeeded;
  752.     dwNeeded = 0;
  753.     dwBuf = 1024;
  754.         if ( (lpbForm = gs_malloc(dwBuf, 1, "win_pr2_getdc")) == (LPBYTE)NULL )
  755.     {
  756.         gs_free(podevmode, size, 1, "win_pr2_getdc");
  757.         gs_free(pidevmode, size, 1, "win_pr2_getdc");
  758.         ClosePrinter(hprinter);
  759.         return FALSE;
  760.     }
  761.     if (GetForm(hprinter, papername, 1, lpbForm, dwBuf, &dwNeeded)) {
  762.         fi1 = (FORM_INFO_1 *)lpbForm;
  763.         pidevmode->dmFields |= DM_FORMNAME;
  764.         SetForm(hprinter, papername, 1, (LPBYTE)fi1);
  765.     }
  766.     gs_free(lpbForm, dwBuf, 1, "win_pr2_getdc");
  767.  
  768.     strcpy(pidevmode->dmFormName, papername);
  769.     pidevmode->dmFields |= DM_FORMNAME;
  770.  
  771. /*
  772.     pidevmode->dmFields &= DM_FORMNAME;
  773.         pidevmode->dmDefaultSource = 0;
  774. */
  775.  
  776.     /* merge the entries */
  777.     DocumentProperties(NULL, hprinter, device, podevmode, pidevmode, DM_IN_BUFFER | DM_OUT_BUFFER);
  778.  
  779.     ClosePrinter(hprinter);
  780.     /* now get a DC */
  781.     wdev->hdcprn = CreateDC(driver, device, NULL, podevmode);
  782.     }
  783.     else 
  784. #endif
  785.     { /* Win16 and Win32s */
  786.     pfnExtDeviceMode(NULL, hlib, podevmode, device, output,
  787.         pidevmode, NULL, DM_IN_BUFFER | DM_OUT_BUFFER);
  788.     /* release the printer driver */
  789.     FreeLibrary(hlib);
  790.     /* now get a DC */
  791.     if (is_win32s)
  792.         strtok(driver, ".");    /* remove .drv */
  793.     wdev->hdcprn = CreateDC(driver, device, output, podevmode);
  794.     }
  795.  
  796.     gs_free(pidevmode, size, 1, "win_pr2_getdc");
  797.     gs_free(podevmode, size, 1, "win_pr2_getdc");
  798.  
  799.     if (wdev->hdcprn != (HDC)NULL) 
  800.     return TRUE;    /* success */
  801.    
  802.     /* fall back to prompting user */
  803.     return FALSE;
  804. }
  805.